/*
 * #%L
 * java model
 * %%
 * Copyright (C) 2009 - 2011 prefabware.com Stefan Isele
 * %%
 * All Rights Reserved.
 * This program is dual-licensed under the GNU General Public license
 * or a commercial license.
 * You may select to use one or the other of these licenses.
 * To obtain a commercial license please contact Stefan Isele at www.stefan-isele.de
 * Any modifications to this file must keep this entire header intact.
 * Redistribution, except as permitted by the selected license, is prohibited.
 * #L%
 */
package com.prefabware.jmodel.expression;

import com.prefabware.jmodel.JMethod;
import com.prefabware.jmodel.JMethodDeclaration;
import com.prefabware.jmodel.JType;
import com.prefabware.jmodel.code.JBlock;
import com.prefabware.jmodel.code.JCodeOptions;

/**
 * @author sisele_job
 *
 */
public class JExpressionUtil {

//	/**
//	 * @param constructor
//	 * @return an invocation of the given constructor
//	 */
//	public static JConstructorInvocation newInvocation(JConstructor constructor) {
//		JClass jClass = constructor.getJClass();
//		// create an invocation that shall be the result of the builder
//		JConstructorInvocation conCall = new JConstructorInvocation(constructor);
//		// add parameters
//		List<JArgument> arguments = constructor.getArguments();
//		for (JArgument argument : arguments) {
//			JVariable var = JTypeUtil.newJVariable(
//					StringUtil.firstLetterLowerCase(jClass.getName()) + "_" + argument.getName(), argument.getDeclaration().getType(),conCall.gfalse,constructor, null);
//			conCall.bind(argument, var);
//		}
//		return conCall;
//	}

	public static JMethodInvocation newInvocation(JExpression target, JMethod method) {
		// JAssignmentTarget result = JTypeUtil.newJVariable("customer",
		// jClass);
		// create an invocation that shall be the result of the builder
		JMethodInvocation conCall = new JMethodInvocation(target, method);
		// the caller has to bind arguments to expressions
		return conCall;
	}

	public static JVariable newThis(JType type, JMethodDeclaration methodDcl) {
		JVariableDeclaration variable = new JVariableDeclarationBase(false,"this",type,null);
		return new JVariableBase(variable);
	}

	public static Return newReturn(JExpression expression) {
		return new Return(expression);
	}

	public static class Return implements JExpression {
		private JExpression expression;

		public Return(JExpression expression) {
			super();
			this.expression = expression;
		}

		@Override
		public String asCode(JCodeOptions options) {
			String code = "return ";
			if (expression != null) {
				code = code + expression.asCode(options);
			}
			return code;
		}
	}

	/**
	 * adds a block with a default implementation for the method. if the method
	 * returns something, the block will contain the definition of a variable
	 * initilized with null and an according return statement;
	 * 
	 * @param method
	 * @return
	 */
	public static JBlock getDefaultImplementation(JMethod method) {
		if (method.getDeclaration().getType().getName().equalsIgnoreCase(void.class.getSimpleName())) {
			// empty return !
			return new JBlock().add(return_());
		} else {
			return new JBlock().add(return_("null"));
		}
		// JType returnType = method.getSignature().getReturnType().getType();
		// JBlock block = new JBlock();
		// if (returnType != TypeFactory.VOID) {
		// Gettable<String, JArgument> gettable = new Gettable<String,
		// JArgument>() {
		//
		// @Override
		// public String get(JArgument from) {
		// return from.getName();
		// }
		// };
		// // avoid duplicate varnames, the return-var may not have the same
		// // name as any argument !
		// List<String> existingNames = CollectionUtil.getList(gettable,
		// method.getArguments());
		// String uniqueName =
		// JavaUtil.getUniqueName(JavaUtil.getVariableName(returnType.getName()),
		// existingNames);
		// JMemberDeclaration dcl = new JMemberDeclaration(uniqueName, returnType, false,
		// JModifiers.NONE,
		// JVisibility.DEFAULT);
		// final JVariable var = new JVariable(dcl);
		// JExpression initializer = new JExpression() {
		//
		// @Override
		// public String asCode() {
		// return " = null";
		// }
		// };
		// var.setInitializer(initializer);
		// JVariableDeclaration vdcl = new JVariableDeclaration(var);
		// block.add(vdcl);
		// block.add(return_(var.getName()));
		// } else {
		// block.add(return_());
		// }
		//
		// return block;
	}

	/**
	 * a simple return statement
	 */
	public static JExpression return_() {
		return new JExpression() {

			@Override
			public String asCode(JCodeOptions options) {
				return "return";
			}
		};
	}

	public static JExpression return_(final String varName) {
		return new JExpression() {

			@Override
			public String asCode(JCodeOptions options) {
				return "return " + varName;
			}
		};
	}

	/**
	 * returns a JExpression with the return statement for
	 * a method with the given type; can be used in empty implementations
	 * @param returnType
	 * @return "return"      if the returnType is void or Void
	 * 		   "return null" else
	 */
	public static JExpression returnFor(JType returnType) {
		if (returnType.isVoid()) {
//			return return_();
			return JEmptyExpression.create();
		} else {
			return return_("null");
		}
	}
}
